import pandas as pd
import os
import time
import requests
import json
import base64
import uuid
import random
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from moviepy.editor import *
from moviepy.video.tools.drawing import color_gradient
import dashscope
from src.processors.oss_uploader import upload_file_and_get_url
from src.processors.i2v_processor import process_single_image_with_audio

def read_excel_data(excel_path):
    """
    读取Excel文件中的比赛信息
    
    Args:
        excel_path (str): Excel文件路径
        
    Returns:
        list: 包含比赛信息的字典列表
    """
    try:
        # 读取Excel文件
        df = pd.read_excel(excel_path)
        
        print(f"从Excel文件 {excel_path} 中读取到 {len(df)} 行数据")
        # 打印列名用于调试
        print("Excel列名:", df.columns.tolist())
        
        # 检查是否包含所需的列
        required_columns = ['比赛时间', '球队A', '球队A队标链接', '球队B', '球队B队标链接', '文案']
        missing_columns = [col for col in required_columns if col not in df.columns]
        if missing_columns:
            raise Exception(f"Excel文件缺少必要的列: {missing_columns}")
        
        # 提取所需列信息
        matches_data = []
        for index, row in df.iterrows():
            # 跳过完全空的行（通常是表头后的空行）
            if pd.isna(row['比赛时间']) and pd.isna(row['球队A']) and pd.isna(row['球队B']):
                print(f"跳过空行: 第 {index+1} 行")
                continue
                
            # 处理可能的NaN值并去除首尾空格
            match_time = row['比赛时间']
            team_a = row['球队A']
            team_a_logo = row['球队A队标链接']
            team_b = row['球队B']
            team_b_logo = row['球队B队标链接']
            copywriting = row['文案']
            
            # 处理NaN值并去除首尾空格
            match_time = '' if pd.isna(match_time) else str(match_time).strip()
            team_a = '' if pd.isna(team_a) else str(team_a).strip()
            team_a_logo = '' if pd.isna(team_a_logo) else str(team_a_logo).strip()
            team_b = '' if pd.isna(team_b) else str(team_b).strip()
            team_b_logo = '' if pd.isna(team_b_logo) else str(team_b_logo).strip()
            copywriting = '' if pd.isna(copywriting) else str(copywriting).strip()
            
            # 跳过关键字段都为空的行
            if not match_time and not team_a and not team_b:
                print(f"跳过关键字段为空的行: 第 {index+1} 行")
                continue
            
            match_info = {
                'match_time': match_time,          # 日期+时间
                'team_a': team_a,                  # 主队名称
                'team_a_logo': team_a_logo,        # 主队队标链接
                'team_b': team_b,                  # 客队名称
                'team_b_logo': team_b_logo,        # 客队队标链接
                'copywriting': copywriting         # 文案
            }
            matches_data.append(match_info)
            print(f"读取到第 {index+1} 行比赛数据: 时间='{match_time}', 球队A='{team_a}', 球队B='{team_b}'")  # 调试信息
        
        print(f"总共读取到 {len(matches_data)} 条比赛数据")
        return matches_data
    except Exception as e:
        raise Exception(f"读取Excel文件失败: {str(e)}")


def generate_background_poster(api_key, prompt_text, wh_ratios="竖版", output_path=None):
    """
    使用AI生成没有文本和图标的背景海报
    
    Args:
        api_key (str): DashScope API密钥
        prompt_text (str): 提示词（仅包含背景描述）
        wh_ratios (str): 宽高比，"竖版"或"横版"
        output_path (str): 输出图片路径
        
    Returns:
        tuple: (成功状态, 结果信息或错误信息)
    """
    try:
        # 设置API基础URL
        dashscope.base_http_api_url = 'https://dashscope.aliyuncs.com/api/v1'
        
        # 根据宽高比设置图片尺寸
        if wh_ratios == "横版":
            size = "1664*928"  # 横版使用1664*928
        else:
            size = "928*1664"  # 竖版使用928*1664
        
        # 构造请求数据
        data = {
            "model": "qwen-image-plus",
            "input": {
                "prompt": prompt_text
            },
            "parameters": {
                "size": size,
                "n": 1,
                "prompt_extend": True,
                "watermark": False
            }
        }
        
        # 设置请求头
        headers = {
            'X-DashScope-Async': 'enable',
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {api_key}'
        }
        
        print(f"正在提交海报生成任务...")
        print(f"提示词: {prompt_text}")
        print(f"尺寸: {size}")
        
        # 提交海报生成任务
        response = requests.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis',
            headers=headers,
            json=data
        )
        
        if response.status_code != 200:
            error_msg = f"海报生成任务提交失败，状态码: {response.status_code}，响应: {response.text}"
            print(error_msg)
            return False, error_msg
        
        response_data = response.json()
        print(f"海报生成API响应: {response_data}")
        
        # 检查响应中是否包含任务ID
        if 'output' not in response_data or 'task_id' not in response_data['output']:
            error_msg = f"海报生成任务提交成功，但响应中未包含task_id字段。完整响应: {response_data}"
            print(error_msg)
            return False, error_msg
        
        task_id = response_data['output']['task_id']
        print(f"海报生成任务已提交，任务ID: {task_id}")
        
        # 等待任务完成
        image_url = None
        task_status = None
        max_attempts = 60  # 最多等待10分钟(60次*10秒)
        attempt = 0
        
        while attempt < max_attempts:
            print(f"正在等待海报生成完成... (尝试 {attempt+1}/{max_attempts})")
            time.sleep(10)  # 等待10秒后查询状态
            
            # 查询任务状态
            status_response = requests.get(
                f'https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}',
                headers={'Authorization': f'Bearer {api_key}'}
            )
            
            print(f"任务状态查询响应状态码: {status_response.status_code}")
            
            if status_response.status_code == 200:
                status_data = status_response.json()
                print(f"任务状态查询完整响应: {status_data}")
                
                if 'output' not in status_data or 'task_status' not in status_data['output']:
                    error_msg = f"任务状态查询成功，但响应中未包含task_status字段。完整响应: {status_data}"
                    print(error_msg)
                    return False, error_msg
                
                task_status = status_data['output']['task_status']
                print(f"任务状态: {task_status}")
                
                # 检查任务是否失败
                if task_status == 'FAILED':
                    error_message = status_data.get('output', {}).get('message', '未知错误')
                    error_code = status_data.get('output', {}).get('code', '未知错误码')
                    error_msg = f"海报生成失败: 错误码 {error_code}, 错误信息: {error_message}"
                    print(error_msg)
                    return False, error_msg
                elif task_status == 'SUCCEEDED':
                    if 'results' not in status_data['output'] or not status_data['output']['results']:
                        error_msg = f"任务执行成功，但响应中未包含results字段或结果为空。完整响应: {status_data}"
                        print(error_msg)
                        return False, error_msg
                    
                    # 获取生成的图片URL
                    image_url = status_data['output']['results'][0]['url']
                    print(f"海报生成完成，URL: {image_url}")
                    break
                elif task_status == 'CANCELED':
                    error_msg = "海报生成任务已取消"
                    print(error_msg)
                    return False, error_msg
            else:
                error_msg = f"查询任务状态失败，状态码: {status_response.status_code}，响应内容: {status_response.text}"
                print(error_msg)
            
            attempt += 1
        
        if not image_url:
            error_msg = f"海报生成超时，最终任务状态: {task_status}"
            print(error_msg)
            return False, error_msg
        
        # 如果提供了输出路径，则下载图片
        if output_path:
            print("正在下载海报图片...")
            image_data = requests.get(image_url)
            if image_data.status_code == 200:
                with open(output_path, 'wb') as f:
                    f.write(image_data.content)
                print(f"海报图片已保存到: {output_path}")
                return True, output_path
            else:
                error_msg = f"下载海报图片失败，状态码: {image_data.status_code}"
                print(error_msg)
                return False, error_msg
        else:
            # 如果没有提供输出路径，直接返回URL
            return True, image_url
            
    except Exception as e:
        error_msg = f"海报生成过程中出错: {str(e)}"
        print(error_msg)
        return False, error_msg


def base64_to_temp_image(base64_string, prefix="team_logo"):
    """
    将base64字符串转换为临时图片文件并保存
    
    Args:
        base64_string (str): base64编码的图片数据
        prefix (str): 文件名前缀
        
    Returns:
        str: 保存的文件路径，如果失败则返回None
    """
    try:
        # 检查是否是有效的base64字符串
        if not base64_string or not base64_string.startswith('data:image'):
            return None
            
        # 解析base64数据
        header, encoded_data = base64_string.split(',', 1)
        file_extension = header.split('/')[1].split(';')[0]
        
        # 解码base64数据
        image_data = base64.b64decode(encoded_data)
        
        # 生成临时文件名
        filename = f"{prefix}_{random.randint(1000, 9999)}.{file_extension}"
        temp_dir = os.path.join(os.getcwd(), 'temp')
        os.makedirs(temp_dir, exist_ok=True)
        file_path = os.path.join(temp_dir, filename)
        
        # 保存图片文件
        with open(file_path, 'wb') as f:
            f.write(image_data)
            
        return file_path
    except Exception as e:
        print(f"Base64转换为图片文件失败: {e}")
        return None


def add_text_and_logos_to_image(image_path, output_path, match_info):
    """
    在图片上添加文本和队伍图标
    
    Args:
        image_path (str): 原始图片路径
        output_path (str): 输出图片路径
        match_info (dict): 比赛信息
        
    Returns:
        bool: 是否成功
    """
    try:
        # 打开背景图片
        bg_image = Image.open(image_path).convert("RGBA")
        width, height = bg_image.size
        
        # 创建一个可以在上面绘制的对象
        draw = ImageDraw.Draw(bg_image)
        
        # 尝试加载中文字体，如果失败则使用默认字体
        try:
            # Windows系统字体路径
            font_large = ImageFont.truetype("arialuni.ttf", 80)
            font_medium = ImageFont.truetype("arialuni.ttf", 60)
            font_small = ImageFont.truetype("arialuni.ttf", 40)
        except:
            # 使用默认字体
            font_large = ImageFont.load_default()
            font_medium = ImageFont.load_default()
            font_small = ImageFont.load_default()
        
        # 添加比赛标题 (球队A vs 球队B)
        title_text = f"{match_info['team_a']} vs {match_info['team_b']}"
        # 计算文本位置使其居中
        left, top, right, bottom = draw.textbbox((0, 0), title_text, font=font_large)
        text_width = right - left
        text_height = bottom - top
        x = (width - text_width) // 2
        y = height // 8  # 放在图片上部1/8处
        
        # 添加文本阴影效果
        draw.text((x-2, y-2), title_text, font=font_large, fill=(0, 0, 0, 128))
        draw.text((x+2, y+2), title_text, font=font_large, fill=(0, 0, 0, 128))
        draw.text((x, y), title_text, font=font_large, fill=(255, 255, 255, 255))
        
        # 添加比赛时间
        time_text = match_info['match_time']
        left, top, right, bottom = draw.textbbox((0, 0), time_text, font=font_medium)
        text_width = right - left
        x = (width - text_width) // 2
        y = height // 4  # 放在图片1/4处
        
        draw.text((x-1, y-1), time_text, font=font_medium, fill=(0, 0, 0, 128))
        draw.text((x+1, y+1), time_text, font=font_medium, fill=(0, 0, 0, 128))
        draw.text((x, y), time_text, font=font_medium, fill=(255, 255, 0, 255))  # 黄色
        
        # 添加文案
        copywriting = match_info['copywriting']
        left, top, right, bottom = draw.textbbox((0, 0), copywriting, font=font_small)
        text_width = right - left
        x = (width - text_width) // 2
        y = height * 3 // 4  # 放在图片下部
        
        draw.text((x-1, y-1), copywriting, font=font_small, fill=(0, 0, 0, 128))
        draw.text((x+1, y+1), copywriting, font=font_small, fill=(0, 0, 0, 128))
        draw.text((x, y), copywriting, font=font_small, fill=(255, 255, 255, 255))
        
        # 处理队伍图标
        team_a_logo_path = base64_to_temp_image(match_info['team_a_logo'], "team_a_logo")
        team_b_logo_path = base64_to_temp_image(match_info['team_b_logo'], "team_b_logo")
        
        logo_size = 120  # 图标大小
        
        if team_a_logo_path:
            try:
                team_a_logo = Image.open(team_a_logo_path).convert("RGBA")
                team_a_logo = team_a_logo.resize((logo_size, logo_size))
                
                # 放置在左下方
                x = width // 4 - logo_size // 2
                y = height * 5 // 8
                bg_image.paste(team_a_logo, (x, y), team_a_logo)
            except Exception as e:
                print(f"处理队伍A图标时出错: {e}")
        
        if team_b_logo_path:
            try:
                team_b_logo = Image.open(team_b_logo_path).convert("RGBA")
                team_b_logo = team_b_logo.resize((logo_size, logo_size))
                
                # 放置在右下方
                x = width * 3 // 4 - logo_size // 2
                y = height * 5 // 8
                bg_image.paste(team_b_logo, (x, y), team_b_logo)
            except Exception as e:
                print(f"处理队伍B图标时出错: {e}")
        
        # 保存最终图片
        bg_image.convert("RGB").save(output_path)
        print(f"已保存带文本和图标的图片: {output_path}")
        
        # 清理临时文件
        if team_a_logo_path and os.path.exists(team_a_logo_path):
            os.remove(team_a_logo_path)
        if team_b_logo_path and os.path.exists(team_b_logo_path):
            os.remove(team_b_logo_path)
            
        return True
    except Exception as e:
        print(f"在图片上添加文本和图标时出错: {e}")
        return False


def add_text_and_logos_to_video(video_path, output_path, match_info):
    """
    在视频上添加文本和队伍图标
    
    Args:
        video_path (str): 原始视频路径
        output_path (str): 输出视频路径
        match_info (dict): 比赛信息
        
    Returns:
        bool: 是否成功
    """
    try:
        # 加载视频
        video = VideoFileClip(video_path)
        width, height = video.size
        
        # 创建文本剪辑
        text_clips = []
        
        # 添加比赛标题 (球队A vs 球队B)
        title_text = f"{match_info['team_a']} vs {match_info['team_b']}"
        title_clip = TextClip(title_text, fontsize=80, color='white', stroke_color='black', stroke_width=2, font='Arial-Bold')
        title_clip = title_clip.set_position(('center', height // 8)).set_duration(video.duration)
        text_clips.append(title_clip)
        
        # 添加比赛时间
        time_text = match_info['match_time']
        time_clip = TextClip(time_text, fontsize=60, color='yellow', stroke_color='black', stroke_width=1, font='Arial-Bold')
        time_clip = time_clip.set_position(('center', height // 4)).set_duration(video.duration)
        text_clips.append(time_clip)
        
        # 添加文案
        copywriting = match_info['copywriting']
        copywriting_clip = TextClip(copywriting, fontsize=40, color='white', stroke_color='black', stroke_width=1, font='Arial')
        copywriting_clip = copywriting_clip.set_position(('center', height * 3 // 4)).set_duration(video.duration)
        text_clips.append(copywriting_clip)
        
        # 处理队伍图标
        logo_clips = []
        logo_size = 120
        
        team_a_logo_path = base64_to_temp_image(match_info['team_a_logo'], "team_a_logo")
        team_b_logo_path = base64_to_temp_image(match_info['team_b_logo'], "team_b_logo")
        
        if team_a_logo_path:
            try:
                team_a_logo_clip = ImageClip(team_a_logo_path).set_duration(video.duration)
                team_a_logo_clip = team_a_logo_clip.resize((logo_size, logo_size))
                # 添加一些动画效果
                team_a_logo_clip = team_a_logo_clip.set_position(
                    lambda t: (width // 4 - logo_size // 2, height * 5 // 8)
                )
                logo_clips.append(team_a_logo_clip)
            except Exception as e:
                print(f"处理队伍A视频图标时出错: {e}")
        
        if team_b_logo_path:
            try:
                team_b_logo_clip = ImageClip(team_b_logo_path).set_duration(video.duration)
                team_b_logo_clip = team_b_logo_clip.resize((logo_size, logo_size))
                # 添加一些动画效果
                team_b_logo_clip = team_b_logo_clip.set_position(
                    lambda t: (width * 3 // 4 - logo_size // 2, height * 5 // 8)
                )
                logo_clips.append(team_b_logo_clip)
            except Exception as e:
                print(f"处理队伍B视频图标时出错: {e}")
        
        # 合成最终视频
        final_clips = [video] + text_clips + logo_clips
        final_video = CompositeVideoClip(final_clips)
        
        # 添加淡入淡出效果
        final_video = final_video.fadein(0.5).fadeout(0.5)
        
        # 输出视频
        final_video.write_videofile(output_path, codec='libx264', audio_codec='aac')
        
        # 清理临时文件
        if team_a_logo_path and os.path.exists(team_a_logo_path):
            os.remove(team_a_logo_path)
        if team_b_logo_path and os.path.exists(team_b_logo_path):
            os.remove(team_b_logo_path)
            
        return True
    except Exception as e:
        print(f"在视频上添加文本和图标时出错: {e}")
        return False


def process_match_videos_from_excel(excel_path, audios_dir, output_dir, api_key, language="zh"):
    """
    处理Excel中的比赛信息，为每场比赛生成带有文本和图标的视频
    
    Args:
        excel_path (str): Excel文件路径
        audios_dir (str): 音频目录
        output_dir (str): 输出目录
        api_key (str): DashScope API密钥
        language (str): 生成语言，'zh'表示中文，'vi'表示越南语
        
    Returns:
        list: 处理结果列表
    """
    print(f"开始处理视频: Excel={excel_path}")
    
    # 读取Excel数据
    matches_data = read_excel_data(excel_path)
    if not matches_data:
        return []
    
    # 确保输出目录存在
    images_output_dir = os.path.join(output_dir, 'images')
    videos_dir = os.path.join(output_dir, 'videos')
    os.makedirs(images_output_dir, exist_ok=True)
    os.makedirs(videos_dir, exist_ok=True)
    print(f"创建/确认图片输出目录: {images_output_dir}")
    print(f"创建/确认视频输出目录: {videos_dir}")
    
    results = []
    
    # 获取音频文件
    audio_files = []
    audios_path = Path(audios_dir)
    for ext in ['*.mp3', '*.wav', '*.aac', '*.flac', '*.m4a']:
        audio_files.extend(audios_path.glob(ext))
    
    print(f"在音频目录 {audios_dir} 中找到 {len(audio_files)} 个音频文件")
    
    if not audio_files:
        print("警告: 未找到音频文件，将跳过所有视频生成")
    
    # 处理每场比赛
    for i, match_info in enumerate(matches_data):
        try:
            print(f"正在处理第 {i+1}/{len(matches_data)} 项: {match_info['team_a']} vs {match_info['team_b']}")
            
            # 生成文件名
            safe_team_a = "".join(c for c in match_info['team_a'] if c.isalnum() or c in (' ', '-', '_')).rstrip()
            safe_team_b = "".join(c for c in match_info['team_b'] if c.isalnum() or c in (' ', '-', '_')).rstrip()
            
            # 生成背景海报
            bg_filename = f"{safe_team_a}_vs_{safe_team_b}_bg_{uuid.uuid4().hex[:8]}.png"
            bg_output_path = os.path.join(images_output_dir, bg_filename)
            
            # 生成带文本和图标的海报
            final_filename = f"{safe_team_a}_vs_{safe_team_b}_final_{uuid.uuid4().hex[:8]}.png"
            final_output_path = os.path.join(images_output_dir, final_filename)
            
            # 构造背景海报生成参数
            prompt_text = "足球场鸟瞰图，绿色草坪，专业体育场，写实风格，不包含任何文字或图标"
            
            # 生成背景海报
            success, result = generate_background_poster(
                api_key=api_key,
                prompt_text=prompt_text,
                wh_ratios="竖版",
                output_path=bg_output_path
            )
            
            if not success:
                results.append({
                    'match_info': match_info,
                    'image_path': None,
                    'status': 'failed',
                    'message': f"背景海报生成失败: {result}"
                })
                print(f"  背景海报生成失败: {result}")
                continue
            
            print(f"  背景海报生成成功: {bg_output_path}")
            
            # 在背景海报上添加文本和图标
            add_success = add_text_and_logos_to_image(bg_output_path, final_output_path, match_info)
            if not add_success:
                results.append({
                    'match_info': match_info,
                    'image_path': bg_output_path,
                    'status': 'failed',
                    'message': "添加文本和图标失败"
                })
                print(f"  添加文本和图标失败")
                continue
                
            print(f"  带文本和图标的海报生成成功: {final_output_path}")
            
            # 生成视频
            video_filename = f"{safe_team_a}_vs_{safe_team_b}_{uuid.uuid4().hex[:8]}.mp4"
            video_temp_path = os.path.join(videos_dir, f"temp_{video_filename}")
            video_output_path = os.path.join(videos_dir, video_filename)
            
            if not audio_files:
                results.append({
                    'match_info': match_info,
                    'image_path': final_output_path,
                    'status': 'failed',
                    'message': '未找到音频文件'
                })
                print("  跳过（未找到音频文件）")
                continue
            
            # 随机选择一个音频文件
            selected_audio = random.choice(audio_files)
            print(f"  选择音频文件: {selected_audio.name}")
            
            # 生成视频描述
            prompt = f"比赛：{match_info['team_a']} vs {match_info['team_b']}，时间：{match_info['match_time']}。要求：让图片动起来，可以轻微移动镜头，丰富画面细节，但不能出现与原始图片无关的内容，保持原始图片的布局和元素不变。"
            print(f"  视频生成提示词: {prompt}")
            
            # 生成视频
            success, logs = process_single_image_with_audio(
                final_output_path, 
                prompt, 
                "1080P",  # 默认分辨率
                [str(selected_audio)], 
                video_temp_path,
                "",  # 空的负面提示词
                duration=5.0  # 固定时长5秒
            )
            
            if not success:
                results.append({
                    'match_info': match_info,
                    'image_path': final_output_path,
                    'video_path': None,
                    'status': 'failed',
                    'message': f"视频生成失败: {logs}"
                })
                print(f"  视频生成失败: {logs}")
                continue
            
            print(f"  视频生成成功: {video_temp_path}")
            
            # 在视频上添加文本和图标（增强效果）
            add_success = add_text_and_logos_to_video(video_temp_path, video_output_path, match_info)
            if not add_success:
                # 如果添加失败，使用原始生成的视频
                os.rename(video_temp_path, video_output_path)
                print(f"  使用原始生成的视频: {video_output_path}")
            else:
                # 删除临时视频文件
                if os.path.exists(video_temp_path):
                    os.remove(video_temp_path)
                print(f"  带文本和图标的视频生成成功: {video_output_path}")
            
            results.append({
                'match_info': match_info,
                'image_path': final_output_path,
                'video_path': video_output_path,
                'status': 'success',
                'message': '处理成功'
            })
            print(f"  处理成功")
                
        except Exception as e:
            results.append({
                'match_info': match_info,
                'status': 'error',
                'message': str(e)
            })
            print(f"  处理过程中发生错误: {str(e)}")
    
    print(f"视频处理完成，成功处理 {len([r for r in results if r['status'] == 'success'])}/{len(results)} 项")
    return results